home *** CD-ROM | disk | FTP | other *** search
- /*
- ***********************************************************************
- *
- * The set of functions below let a (backgound) application post
- * synchronous or asynchronous notification messages to the user.
- * Synchronous posting means that the posting function does not return until
- * the notification message is displayed and the user dismisses it.
- * In asynchronous mode, the posting function returns as soon as the
- * message is queued into the notification queue (but not yet displayed!).
- * The functions use the Notification Manager and the EventManager (via
- * function sleep() defined elsewhere to relinquish the CPU control while
- * sleeping).
- *
- * Synchronization between the Notification Manager and the present functions
- * A field nmRefCon of the Notification Queue element is used for the
- * synchronization: it is reset to 0 when the element is queued and set to
- * 1 by a completion routine when the message has been posted.
- *
- ***********************************************************************
- */
-
- /* MacHeaders Included */
- #include "mymenv.h"
- #include <string.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include <Notification.h>
-
-
- // Completion routine
- static pascal On_completion(NMRecPtr el)
- {
- NMRemove(el); // Remove the notification request from
- // the manager's queue
- el->nmRefCon = 1; // Mark the notification element as posted
- return 0;
- }
-
- // Create a new notification element
- static NMRecPtr new_element(const char * mesg)
- {
- // Allocate space for the element and the string
- NMRecPtr el = (NMRecPtr)NewPtr(sizeof(NMRec) + sizeof(Str255));
- el->qLink = 0;
- el->qType = nmType;
- el->nmMark = 0;
- el->nmIcon = nil;
- el->nmSound = nil; // String is allocated right after the
- el->nmStr = (unsigned char *)((char *)el + sizeof(NMRec)); // element
- el->nmResp = NewNMProc(On_completion);
- el->nmRefCon = 0;
-
- xstrncpy((char *)(el->nmStr),mesg,254);
- CtoPstr((char *)el->nmStr);
-
- return el;
- }
-
- // Wait until the given element is marked as
- // completed (nmRefCon changes its value from 0
- // to 1).
- // The waiting though busy is gracious enough to let
- // other processes running.
- static void wait_for_completion(NMRecPtr el)
- {
- assert( el != 0 );
- while( el->nmRefCon == 0 )
- sleep(10);
- assert( el->nmRefCon == 1 );
- }
-
- // Simply check if a request is posted
- static Boolean check_if_posted(const NMRecPtr el)
- {
- return el->nmRefCon == 0 ? FALSE : TRUE;
- }
-
- // Dispose of the element
- static void dispose_element(NMRecPtr el)
- {
- assert( el != 0 );
- DisposePtr((char *)el);
- }
-
- /*
- *----------------------------------------------------------------------------
- * Managing the queue of pending notification requests
- * Note the queue is just a circular list
- */
-
- #define Queue_size 5
- static NMRecPtr Queue[Queue_size];
- static unsigned int Queue_free_slot_no = 0;
- static unsigned int Queue_no_filled_slots = 0;
-
- // Enqueue the element. return FALSE if the queue
- // is filled up
- static Boolean enqueue(const NMRecPtr el)
- {
- if( Queue_no_filled_slots >= Queue_size )
- return FALSE; // The queue is filled up
- Queue[Queue_free_slot_no] = el;
- Queue_no_filled_slots++;
- if( ++Queue_free_slot_no >= Queue_size ) // Adjust the pointer in a circular way
- Queue_free_slot_no = 0;
- return TRUE;
- }
-
- // Return the head elememt of the queue, or 0 if the
- // queue is empty
- static NMRecPtr get_head(void)
- {
- register int index;
- if( Queue_no_filled_slots == 0 )
- return (NMRecPtr)0;
-
- assert( Queue_free_slot_no < Queue_size );
- index = Queue_free_slot_no - Queue_no_filled_slots;
- if( index < 0 )
- index += Queue_size;
- return Queue[index];
- }
-
- // Remove the head of the queue
- static void remove_head(void)
- {
- register NMRecPtr el;
- assert( Queue_no_filled_slots > 0 && Queue_no_filled_slots <= Queue_size );
- el = get_head();
- dispose_element(el);
- Queue_no_filled_slots--;
- }
-
- // Check out if some request in the queue of pending
- // request have been posted. If so, remove them
- // from the queue.
- // Note that we expect requests are posted in the
- // order they enqueued, i.e. in the FIFO order
- static void check_queue(void)
- {
- register NMRecPtr el;
-
- while( (el=get_head()) != (NMRecPtr)0 && check_if_posted(el) )
- remove_head();
- }
-
- /*
- *----------------------------------------------------------------------------
- * Routing modules
- */
-
- void notify_and_wait(const char * messg,...)
- {
- va_list args;
- char buffer[300];
- register NMRecPtr el;
-
- va_start(args,messg); // Init 'args' to the beginning of
- // the variable length list of args
- assert(strlen(messg) < sizeof(buffer)-100);
- vsprintf(buffer,messg,args);
-
- check_queue();
- el = new_element(buffer);
- assert( NMInstall(el) == noErr );
- wait_for_completion(el);
- dispose_element(el);
- }
-
- // Asynchronous notification
- void notify(const char * messg,...)
- {
- va_list args;
- char buffer[300];
- register NMRecPtr el;
-
- va_start(args,messg); // Init 'args' to the beginning of
- // the variable length list of args
- assert(strlen(messg) < sizeof(buffer)-100);
- vsprintf(buffer,messg,args);
-
- check_queue();
- el = new_element(buffer);
- assert( NMInstall(el) == noErr );
- while( !enqueue(el) ) // If there are too many outstanding
- { // elements, wait until some are posted
- wait_for_completion(get_head());
- check_queue();
- }
- }
-
-